package com.dilidili.config;

import com.dilidili.service.impl.UsersDetailServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.annotation.Resource;


@EnableAuthorizationServer
@Configuration
public class OauthConfig extends AuthorizationServerConfigurerAdapter {
    //注入认证管理器
    @Resource
    private AuthenticationManager authenticationManager;
    //注入获取用户身份的实现类对象
    @Resource
    private UsersDetailServiceImpl usersDetailServiceImpl;


    /**
     * 配置jwt生成和解析的需要的秘钥
     *
     * @return
     */
    @Bean
    protected JwtAccessTokenConverter jwtAccessTokenConverter() {
        MyJwtAccessTokenConverter jwtAccessTokenConverter = new MyJwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("dev");
        return jwtAccessTokenConverter;
    }

    /**
     * 在spring容器中放置JwtTokenStore 注意 生成jwt需要秘钥所有需要注入
     * JwtAccessTokenConverter
     */
    @Bean
    protected TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    //配置认证凭证信息 这里配置jwtAccessTokenConverter是因为解析jwt需要秘钥
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        /* 测试生成jwt格式的token资源服务器改造
        资源服务端 其实默认使用的就是Jwt的token 所以把配置的tokenService去掉*/
        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter()).authenticationManager(authenticationManager)
                .userDetailsService(usersDetailServiceImpl);
    }

    /**
     * 密码匹配器
     *
     * @return
     */
    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }



    /**
     * 配置第三方客户端信息，把第三方客户端信息放到内存中
     *
     * @param clients
     * @throws Exception
     */
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //把
        clients.inMemory()
                //客户端id
                .withClient("user-client")
                //客户端密码
                .secret(new BCryptPasswordEncoder().encode("user-secret-8888"))
                /**
                 * 支持哪些认证模式
                 * authorization_code 授权码模式
                 * password 密码模式
                 * implicit 简单模式
                 * client_credentials 客户端模式
                 * refresh_token 这个不是一种模式 是支持刷新令牌的意思
                 */
                .authorizedGrantTypes("authorization_code", "password", "implicit",
                        "client_credentials", "refresh_token")
                //token有效期 50分钟
                .accessTokenValiditySeconds(1440 * 60)
                //刷新token有效期 24小时
                .refreshTokenValiditySeconds(24 * 3600)
                //权限范围
                .scopes("all")
                //授权码模式手动校验 不自动校验
                .autoApprove(false)
                //第三方客户端回调地址 用来返回验证码
                .redirectUris("http://www.baidu.com");
    }

    /**
     * 配置安全策略
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws
            Exception {
        //security.支持远程token访问.支持远程token校验.让密码模式获取令牌的时
        //候/oauth/token支持client_id以及client_secret作为form参数做登录认证
        security.tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
    }
}
